home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Graphics Plus
/
Graphics Plus.iso
/
general
/
modelers
/
geomview
/
source.lha
/
Geomview
/
tools
/
lisp2c
< prev
next >
Wrap
Text File
|
1993-11-10
|
8KB
|
287 lines
#! /bin/sh
########################################################################
# usage: lisp2c [-cprefix prefix] -o OUTFILE [ FILE1 ... ]
#
# writes OUTFILE.c and OUTFILE.h, if results would differ from
# existing files of those names.
#
# If -cprefix is specified, uses "prefix_" as the prefix for C
# function names. Default prefix is "l_".
#
# This script scans the input files, or standard input if no input
# files are specified, generating a C interface to each lisp function
# defined via the "DEFINE" and "LDECLARE" macros (defined in
# geomview's "lispext.h" file). It assumes usage of the following
# form in the input files:
#
# DEFINE(name, ltype,
# docstring)
# {
# <local variable declarations and initializations>
# LDECLARE(("lname", LBEGIN,
# <argspec>,
# ...,
# LEND));
# ...
# return L...;
# }
#
# Specifically:
#
#
# 1. The first line of the call to DEFINE must contain exactly, in
# this order:
# 1.1. the word DEFINE
# 1.2. a left paren
# 1.3. a name which is a valid C identifier. There must be no
# spaces between the left paren and the name. This name with
# an "L" prepended becomes the name of the low-level C
# procedure (the one whose body follows the DEFINE call),
# and with a "l_" prepended becomes the name of the C
# interface to the corresponding lisp function (unless an
# alternate prefix is specified with the -cprefix argument
# to this script).
# 1.4 a comma (possibly preceeded and/or followed by spaces or
# tabs)
# 1.5 a lisp type name (like LINT or LGEOM etc) which indicates
# the type of the lisp object returned by this function.
# 1.6 a comma (possibly preceeded and/or followed by spaces or
# tabs)
#
# 2. The rest of the DEFINE call consists of the docstring argument,
# which must be a single string and may be broken over any number
# of lines.
#
#
# 3. The first line of the call to LDECLARE must contain, in this order:
# 1.1. the word LDECLARE
# 1.2. two left parens
# 1.3. a string which becomes the lisp name of the function
# 1.4 a comma (possibly preceeded and/or followed by spaces or
# tabs)
# 1.5 the word LBEGIN
# 1.6 a comma (possibly preceeded and/or followed by spaces or
# tabs)
#
# 4. Intermediate lines of the LDECLARE call must contain one
# <argspec> per line; where <argspec> is either the word LOPTIONAL
# or something with the syntax
#
# [ modifier, ] ltype, address
#
# where modifier is one of LHOLD or LLITERAL, ltype is a lisp type
# name, and address is the address of a local variable into which
# the corresponding argument's value is to be loaded. Any
# arguments following LOPTIONAL are taken to be optional.
#
# 5. The last line of the LDECLARE call must contain just the string
# "LEND));" possibly preceeded by spaces or tabs.
#
# This script generates the C interface (consisting of the function
# declaration in OUTFILE.h and the function itself in OUTFILE.c) only
# for functions which use both the DEFINE and LDECLARE macros. To
# prevent the generation of a C interface for a particular function,
# preceed the word LDECLARE by a comment on the same line, as in:
#
#
# /*NOC*/ LDECLARE(("foo, LBEGIN,
#
# The contents of the comment are irrelvant; its purpose is simply
# to arrange that LDECLARE is not the first thing on its line.
cprefix="l_" ;
outfile=""
while : ; do
case $1 in
-cprefix)
cprefix=$2 ;
shift 2 ;
;;
-o)
outfile=$2 ;
outstem=`basename $outfile`
shift 2 ;
;;
*)
break ;
;;
esac
done
cfile=/tmp/lisp2c.out.c
hfile=/tmp/lisp2c.out.h
/bin/rm -f $cfile $hfile
# start with an empty .h file in case the awk script below doesn't
# output anything to it:
touch $hfile
cat $* |
# first turn all parens, semicolons, and commas into spaces
tr '();,' ' ' |
# now let awk do its thing
awk '
BEGIN { cprefix="'$cprefix'" ;
outfile="'$outfile'" ;
outstem="'$outstem'" ;
hfile="'$hfile'" ;
fcount = 0 ;
inldeclare=0 ;
type["LINT"] = "int" ;
type["LFLOAT"] = "float" ;
type["LSTRING"] = "char *" ;
type["LLIST"] = "LList *" ;
type["LLOBJECT"] = "LObject *" ;
type["LID"] = "int" ;
type["LKEYWORD"] = "int" ;
type["LSTRINGS"] = "char *" ;
type["LGEOM"] = "GeomStruct *" ;
type["LCAMERA"] = "CameraStruct *" ;
type["LWINDOW"] = "WindowStruct *" ;
type["LAP"] = "ApStruct *" ;
type["LTRANSFORM"] = "TransformStruct *" ;
type["LTRANSFORMN"] = "TmNStruct *" ;
type["LVOID"] = "void" ;
type["LREST"] = "LList *" ;
}
$1 == "LDEFINE" {
fstem = $2 ; # stem from which function names are built
ftype = $3 ; # functions return type
next ;
}
$1 == "LDECLARE" {
name = substr($2,2,length($2)-2) ; # lisp function name
inldeclare=1 ;
lakearg = 0;
argc = 0 ;
next
}
$NF == "LEND" || atend == 1 {
if (inldeclare) {
# remember data for this function
++fcount;
cname = cprefix fstem ;
fstems[fcount] = fstem ;
cnames[fcount] = cname ;
names[fcount] = name ;
# build the declaration
dec = sprintf "%s %s(", type[ftype], cname ;
for (i=1; i<=argc; ++i) {
if (i>1) dec = dec sprintf ", " ;
if (arg[i] == "LARRAY") {
dec = dec sprintf "%s *a%1d, int a%1dn", type[basetype[i]], i, i ;
} else {
if (type[arg[i]] != "") dec = dec sprintf "%s ", type[arg[i]] ;
else dec = dec sprintf "??? " ;
dec = dec sprintf "a%1d", i ;
}
}
dec = dec sprintf ")" ;
# print the declaration, possibly also in header file
printf "%s\n", dec ;
if (outfile != "") printf "%s;\n", dec > hfile ;
# print the function body
printf "{\n" ;
printf " LObject *val = LEvalFunc(\"%s\",\n", name ;
for (i=1; i<=argc; ++i) {
if (arg[i] == "LARRAY") {
printf "\t\t\t LARRAY, %s, a%1d, a%1dn,\n", basetype[i], i, i ;
} else {
printf "\t\t\t %s, a%1d,\n", arg[i], i ;
}
}
printf "\t\t\t LEND);\n"
if (type[ftype] != "void") {
printf " %s retval;\n", type[ftype] ;
printf " LFROMOBJ(%s)(val, &retval);\n", ftype ;
}
printf " LFree(val);\n"
if (type[ftype] != "void") printf " return retval;\n"
printf "}\n\n"
inldeclare=0 ;
atend = 0;
next
}
}
{ if (inldeclare) {
i = 1;
while (i <= NF) {
if ($i == "LLAKE") {
lakearg = 1; next;
} else if ($i == "LOPTIONAL") {
++i; continue;
} else if ($i == "LHOLD") {
++i; continue;
} else if ($i == "LLITERAL") {
++i; continue;
} else if ($i == "LARRAY") {
++i;
++argc ;
arg[argc] = "LARRAY";
basetype[argc] = $i;
next;
} else if ($i == "LREST") {
++argc;
arg[argc] = $i ;
atend = 1;
next ;
} else {
++argc ;
arg[argc] = $i ;
next ;
}
}
}
}
END {
printf "\n" ;
for (i=1; i<=fcount; ++i) {
printf "extern LObject *L%s(Lake *, LList *);\n", fstems[i] ;
}
printf "\n" ;
for (i=1; i<=fcount; ++i) {
printf "extern char H%s[];\n", fstems[i] ;
}
printf "\n" ;
printf "\nvoid %s_init()\n{\n", outstem ;
for (i=1; i<=fcount; ++i) {
printf " LDefun(\"%s\", L%s, H%s);\n", names[i], fstems[i], fstems[i] ;
}
printf "}\n\n" ;
}
' |
# and send output to "outfile.c" if -o specified, otherwise
# to standard output
if [ "$outfile" != "" ] ; then
cat > $cfile ;
if [ -f $cfile ] && cmp $cfile $outfile.c 1>&- 2>&- ; then
: # no change to $outfile.c
else
/bin/rm -f $outfile.c ;
/bin/mv $cfile $outfile.c
echo $outfile.c
fi
if [ -f $hfile ] && cmp $hfile $outfile.h 1>&- 2>&- ; then
: # no change to $outfile.h
else
/bin/rm -f $outfile.h ;
/bin/mv $hfile $outfile.h
echo $outfile.h
fi
else
cat ;
fi
/bin/rm -f $cfile $hfile